/*
 * Copyright (c) 2015-2018 Sfkj Science And Technology Co.,Ltd.
 * All Rights Reserved.
 * This software is the confidential and proprietary information of
 * Sfkj Science And Technology Co.,Ltd.
 * ("Confidential Information").You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sfkj.
 */
package com.sfkj.walk.config;

import com.sfkj.walk.service.UserAuthenticationProvider;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import javax.servlet.Filter;
import javax.servlet.http.HttpServletResponse;

import static com.sfkj.walk.axon.web.WebContants.*;


@Configuration
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String API_MY_PREFIX = MY_PREFIX + "/**";

    @Autowired
    private CommandGateway commandGateway;
    @Autowired
    private FindByIndexNameSessionRepository sessionRepository;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        log.info("Configuring admin SecurityFilterChain...");
        http.authenticationProvider(authenticationProvider(commandGateway));

        http.sessionManagement()
                .maximumSessions(2)
                .sessionRegistry(sessionRegistry());
        http.csrf().disable();

        http.authorizeRequests()
                .antMatchers(API_MY_PREFIX).authenticated();

        http.logout().logoutUrl(MY_PREFIX + "/logout").logoutSuccessHandler((request, response, authentication) ->
                log.info("Logout successful: {}", authentication.getName())
        );

        http.addFilter(authenticationFilter());

        http.exceptionHandling().authenticationEntryPoint((request, response, authentication) ->
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token 无效或者已过期")
        );
    }

    @Bean
    UserAuthenticationProvider authenticationProvider(CommandGateway commandGateway) {
        return new UserAuthenticationProvider(commandGateway);
    }

    @Bean
    Filter authenticationFilter() throws Exception {
        log.info("Creating authenticationFilter...");
        UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter();
        filter.setPostOnly(false);
        filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(API_PREFIX + "/login"));
        filter.setAuthenticationManager(authenticationManager());
        filter.setAuthenticationSuccessHandler((request, response, authentication) ->
                log.info("Authentication successful: {}", authentication.getName())
        );
        filter.setAuthenticationFailureHandler((request, response, authentication) ->
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "账号或密码错误")
        );
        return filter;
    }


    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    SpringSessionBackedSessionRegistry sessionRegistry() {
        return new SpringSessionBackedSessionRegistry(this.sessionRepository);
    }

}
